#include "EpanWrap.h"

extern "C"
{
#include <epan/epan_dissect.h>
#include <epan/emem.h>
#include <epan/packet.h>
#include <epan/value_string.h>

}

const char * MALFORMED_PACKET_MSG = "[Decoding failure: malformed frame]";
const char * TRUNCATED_PACKET_MSG = "[Decoding failure: the packet was truncated during transmission]";
const char * TYPE_ERROR_MSG = "[Decoding failure: error during dfilter parsing]";
const char * DISSECTOR_ERROR_MSG = "[Decoding failure: error in dissector]";

const std::string EthVirtualDissectorName = "eth";
const std::string EthWithFCSDissectorName = "eth_withfcs";
const std::string EthWoFCSDissectorName = "eth_withoutfcs";

extern "C" const value_string sminmpec_values[]=
{
	{0,""},
	{0,""}
};

void ReportFailure(const char *, va_list)
{
	throw;
}

void ReportOpenFailure(const char *, int, gboolean)
{
	throw;
}

void ReportReadFailure(const char *, int)
{
	throw;
}

void SafeProtoTreeAddText(epan_dissect_t * edt, const char * message)
{
    try
    {
        proto_tree_add_text(edt->tree, edt->tvb, 0, 0, message);    
    }
    catch(...)
    {
        // ignore all exceptions
    }
}

void SafeProtoTreeAddProtocolFormat(epan_dissect_t * edt, const char * message)
{
    try
    {
		int proto_malformed = proto_get_id_by_filter_name("malformed");
		if(proto_malformed != -1)
        {
			proto_tree_add_protocol_format(edt->tree, proto_malformed, edt->tvb, 0, 0, message);
		} 
        else 
        {
		    proto_tree_add_text(edt->tree, edt->tvb, 0, 0, message);
		}
  
    }
    catch(...)
    {
        // ignore all exceptions
    }
}


const std::string & GetEthDissectorName(const frame_data & fd)
{
	if (fd.pkt_len >= 64)
		return EthWithFCSDissectorName;
	else
		return EthWoFCSDissectorName;
}


void epan_dissect_run2(epan_dissect_t * edt, std::string packet, std::string protocol)
{
	frame_data fd;
	fd.pkt_len = (guint32)packet.length();
	fd.cap_len = (guint32)packet.length();
	fd.color_filter = 0;

	fd.pfd = 0;
	p_add_proto_data(&fd, 0, 0);

	dissector_handle_t dissector;
	edt->pi.current_proto = "<Missing Protocol Name>";
	edt->pi.cinfo = NULL;
	edt->pi.fd = &fd;
	edt->pi.pseudo_header = NULL;
	edt->pi.data_src = NULL;
	edt->pi.dl_src.type = AT_NONE;
	edt->pi.dl_src.len = 0;
	edt->pi.dl_src.data = NULL;
	edt->pi.dl_dst.type = AT_NONE;
	edt->pi.dl_dst.len = 0;
	edt->pi.dl_dst.data = NULL;
	edt->pi.net_src.type = AT_NONE;
	edt->pi.net_src.len = 0;
	edt->pi.net_src.data = NULL;
	edt->pi.net_dst.type = AT_NONE;
	edt->pi.net_dst.len = 0;
	edt->pi.net_dst.data = NULL;
	edt->pi.src.type = AT_NONE;
	edt->pi.src.len = 0;
	edt->pi.src.data = NULL;
	edt->pi.dst.type = AT_NONE;
	edt->pi.dst.len = 0;
	edt->pi.dst.data = NULL;
	edt->pi.ethertype = 0;
	edt->pi.ipproto  = 0;
	edt->pi.ipxptype = 0;
	edt->pi.ctype = CT_NONE;
	edt->pi.circuit_id = 0;
	edt->pi.noreassembly_reason = "";
	edt->pi.fragmented = FALSE;
	edt->pi.in_error_pkt = FALSE;
	edt->pi.ptype = PT_NONE;
	edt->pi.srcport  = 0;
	edt->pi.destport = 0;
	edt->pi.match_port = 0;
	edt->pi.match_string = NULL;
	edt->pi.can_desegment = 0;
	edt->pi.want_pdu_tracking = 0;
	edt->pi.p2p_dir = P2P_DIR_UNKNOWN;
	edt->pi.private_data = NULL;
	edt->pi.oxid = 0;
	edt->pi.rxid = 0;
	edt->pi.r_ctl = 0;
	edt->pi.src_idx = 0;
	edt->pi.dst_idx = 0;
	edt->pi.vsan = 0;
	edt->pi.dcectxid = 0;
	edt->pi.dcetransporttype = -1;
	edt->pi.decrypt_gssapi_tvb = 0;
	edt->pi.gssapi_wrap_tvb = NULL;
	edt->pi.gssapi_encrypted_tvb = NULL;
	edt->pi.gssapi_decrypted_tvb = NULL;
	edt->pi.layer_names = NULL;
	edt->pi.link_number = 0;
	edt->pi.annex_a_used = MTP2_ANNEX_A_USED_UNKNOWN;

	TRY {
		edt->tvb = tvb_new_real_data((const guint8 *)packet.c_str(), fd.cap_len, fd.pkt_len);
		/* Add this tvbuffer into the data_src list */
		add_new_data_source(&edt->pi, edt->tvb, "Frame");

		std::string dissectorName = protocol;

		if (dissectorName == EthVirtualDissectorName)
		{
			dissectorName = GetEthDissectorName(fd);
		}

		dissector = find_dissector(dissectorName.c_str());

		if(dissector != NULL)
		  call_dissector(dissector, edt->tvb, &edt->pi, edt->tree);

	}
	CATCH(BoundsError) 
    {
		SafeProtoTreeAddText(edt, TRUNCATED_PACKET_MSG);
	}
	CATCH(ReportedBoundsError) 
    {
		SafeProtoTreeAddProtocolFormat(edt, MALFORMED_PACKET_MSG);
	}
	CATCH(TypeError) 
    {
		SafeProtoTreeAddProtocolFormat(edt, TYPE_ERROR_MSG);
	}
	CATCH(DissectorError) 
    {
		SafeProtoTreeAddProtocolFormat(edt, DISSECTOR_ERROR_MSG);
	}
	FINALLY
	{
		ep_free_all();
	}
	ENDTRY;

	fd.flags.visited = 1;
}